package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.vo.PropertyVo;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.dto.RegisterDto;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.DeviceService;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.DevicePageVo;
import com.zzyl.nursing.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private IoTDAClient iotDAClient;

    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public void synchronous() {
        ListProductsRequest listProductsRequest = new ListProductsRequest();
        listProductsRequest.setLimit(50);
        ListProductsResponse response = iotDAClient.listProducts(listProductsRequest);
        List<ProductSummary> products = response.getProducts();
        redisTemplate.opsForValue().set("iot:productList", products);
    }

    @Override
    public List<ProductVo> allProduct() {
        Object products = redisTemplate.opsForValue().get("iot:productList");
        String jsonProducts = JSONUtil.toJsonStr(products);
        List<ProductVo> list = JSONUtil.toList(jsonProducts, ProductVo.class);
        return list;
    }

    @Override
    public DevicePageVo list(DeviceDto dto) {
        Integer pageNum = dto.getPageNum();
        Integer pageSize = dto.getPageSize();
        String deviceName = dto.getDeviceName();
        Integer locationType = dto.getLocationType();
        String productKey = dto.getProductKey();

        Page<Device> devicePage = new Page<>(pageNum, pageSize);

        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(deviceName != null, Device::getDeviceName, deviceName)
                .eq(locationType != null, Device::getLocationType, locationType)
                .eq(productKey != null, Device::getProductKey, productKey);

        Page<Device> page = deviceMapper.selectPage(devicePage, wrapper);
        DevicePageVo vo = new DevicePageVo();
        vo.setTotal(page.getTotal());
        vo.setRows(page.getRecords());
        log.info("设备列表：{}", vo);
        return vo;
    }

    @Override
    public void register(RegisterDto dto) {
        //校验相同设备名
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Device::getDeviceName, dto.getDeviceName());
        if (ObjectUtil.isNotEmpty(deviceMapper.selectOne(wrapper))) {
            throw new RuntimeException("设备名已存在");
        }

        //校验同位置是否存在相同类型的产品
        Integer physicalLocationType = dto.getPhysicalLocationType();
        wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Device::getBindingLocation, dto.getBindingLocation())
                .eq(Device::getLocationType, dto.getLocationType())
                .eq(physicalLocationType != null, Device::getPhysicalLocationType, physicalLocationType)
                .eq(Device::getProductKey, dto.getProductKey());
        if (ObjectUtil.isNotEmpty(deviceMapper.selectOne(wrapper))) {
            throw new RuntimeException("接入位置已存在相同类型产品");
        }

        //创建设备
        AddDeviceRequest request = new AddDeviceRequest();
        AddDevice body = new AddDevice();

        body.withDeviceName(dto.getDeviceName());
        body.withProductId(dto.getProductKey());
        body.withNodeId(dto.getNodeId());

        request.withBody(body);
        log.info("创建设备请求：{}", request);

        AddDeviceResponse addDevice = iotDAClient.addDevice(request);
        log.info("创建设备：{}", addDevice);

        //拉取设备信息传入数据库
        Device device = new Device();
        device.setIotId(addDevice.getDeviceId());
        device.setBindingLocation(dto.getBindingLocation());
        device.setDeviceDescription(dto.getDeviceDescription());
        device.setDeviceName(dto.getDeviceName());
        device.setLocationType(dto.getLocationType());
        device.setPhysicalLocationType(dto.getPhysicalLocationType());
        device.setNodeId(dto.getNodeId());
        device.setCreateTime(new Date());
        device.setProductKey(dto.getProductKey());
        device.setProductName(addDevice.getProductName());
        device.setRemark(dto.getRemark());
        device.setSecret(addDevice.getAuthInfo().getSecret());

        deviceMapper.insert(device);
    }

    @Override
    public DeviceDetailVo getDeviceByIotId(String iotId) {
        DeviceDetailVo deviceReturn = new DeviceDetailVo();
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<Device>().eq(Device::getIotId, iotId);
        Device deviceSelect = deviceMapper.selectOne(wrapper);
        BeanUtil.copyProperties(deviceSelect, deviceReturn);

        //获取激活时间
        ShowDeviceResponse response = iotDAClient.showDevice(new ShowDeviceRequest().withDeviceId(iotId));
        String activeTime = response.getActiveTime();
        Date date = DateUtil.parse(activeTime);
        date = DateUtil.offset(date, DateField.HOUR, 0);

        String status = response.getStatus();

        deviceReturn.setActiveTime(date);
        deviceReturn.setDeviceStatus(status);
        return deviceReturn;
    }

    @Override
    public List<PropertyVo> queryServiceProperties(String iotId) {
        List<DeviceShadowData> shadow = iotDAClient.showDeviceShadow(new ShowDeviceShadowRequest().withDeviceId(iotId)).getShadow();
        Object properties = shadow.get(0).getReported().getProperties();
        String eventTime = shadow.get(0).getReported().getEventTime();
        Map<String, Object> map = JSONUtil.toBean(JSONUtil.toJsonStr(properties), Map.class);

        List<PropertyVo> propertyVos = new ArrayList<>();
        map.entrySet().forEach(entry -> {
            PropertyVo statusInfo = new PropertyVo();
            statusInfo.setFunctionId(entry.getKey());
            statusInfo.setValue(Float.valueOf("" + entry.getValue()));

            DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX");
            OffsetDateTime offsetDateTime = OffsetDateTime.parse(eventTime, inputFormatter);

            DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
            String formattedTime = offsetDateTime.format(outputFormatter);
            statusInfo.setTime(formattedTime);

            propertyVos.add(statusInfo);
        });
        return propertyVos;
    }

    @Override
    public void delete(String iotId) {
        //删远程
        try {
            iotDAClient.deleteDevice(new DeleteDeviceRequest().withDeviceId(iotId));
        } catch (Exception e) {
            throw new BaseException("删除设备失败");
        }

        //删数据库
        LambdaQueryWrapper<Device> wrapper = new LambdaQueryWrapper<Device>().eq(Device::getIotId, iotId);
        deviceMapper.delete(wrapper);
    }
}
